/**
 * Created on May 18, 2007
 */
package jvs.vfs.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import x.java.lang.System;

/**
 * @author qiangli
 * 
 */
public class Log {

	public static final int TRACE = 0;

	public static final int DEBUG = 1;

	public static final int INFO = 2;

	public static final int WARN = 3;

	public static final int ERROR = 4;

	public static final int NONE = 5;

	public static final String[] LEVEL = { "TRACE", "DEBUG", "INFO", "WARN",
			"ERROR", "NONE" };

	private static class ThreadLocalLogLevel extends InheritableThreadLocal<Integer> {
		public Integer initialValue() {
			String level = x.java.lang.System.getProperty("jvs.debug","INFO");
			java.lang.System.out.println("debug.level: "+level);
			return new Integer(toLevel(level));
		}
	}

	private static ThreadLocal<Integer> logLevel = new ThreadLocalLogLevel();

	public static String format(Collection<Object> c) {
		if (c == null) {
			return "NULL";
		}
		if (c.size() == 0) {
			return "{}";
		}
		StringBuffer sb = new StringBuffer();
		sb.append("{");
		Iterator<Object> it = c.iterator();
		int size = c.size();
		for (int i = 0; i < size - 1; i++) {
			sb.append(it.next() + ",");
		}
		sb.append(it.next());
		sb.append("}");
		return sb.toString();
	}

	public static String format(Object[] a) {
		if (a == null) {
			return "NULL";
		}
		if (a.length == 0) {
			return "[]";
		}
		StringBuffer sb = new StringBuffer();
		sb.append("[");
		for (int i = 0; i < a.length - 1; i++) {
			sb.append(a[i] + ",");
		}

		sb.append(a[a.length - 1]);

		sb.append("]");
		return sb.toString();
	}

	public static String format(Properties p) {
		StringWriter sw = null;
		PrintWriter pw = null;

		try {
			sw = new StringWriter();
			pw = new PrintWriter(sw);
			p.list(pw);
		} finally {
			try {
				sw.close();
			} catch (Exception x) {
			}
			try {
				pw.close();
			} catch (Exception x) {
			}
		}
		return sw.toString();
	}

	public static String format(Throwable t) {
		StringWriter sw = null;
		PrintWriter pw = null;

		try {
			sw = new StringWriter();
			pw = new PrintWriter(sw);
			t.printStackTrace(pw);
		} finally {
			try {
				sw.close();
			} catch (Exception x) {
			}
			try {
				pw.close();
			} catch (Exception x) {
			}
		}
		return sw.toString();
	}

	private static String getClassName(Object obj) {
		String name = obj.getClass().getName();
		try {
			int idx = name.lastIndexOf('.');
			if (idx > 0) {
				name = name.substring(idx + 1);
			}
		} catch (Exception e) {
		}
		return name;
	}

	public static int getLogLevel() {
		Integer o = (Integer) logLevel.get();

		return o.intValue();
	}

	public static void log(int level, Object obj, List<Object> msgs) {
		if (logLevel() <= level) {

			log(LEVEL[level] + ": " + getClassName(obj) + ": " + format(msgs));
		}
	}

	public static void log(int level, Object obj, Object msg) {
		if (logLevel() <= level) {
			log(LEVEL[level] + ": " + getClassName(obj) + ": " + msg);
		}
	}

	public static void log(int level, Object obj, Object[] msgs) {
		if (logLevel() <= level) {

			log(LEVEL[level] + ": " + getClassName(obj) + ": " + format(msgs));
		}
	}

	public static void log(int level, Object obj, Properties prop) {
		if (logLevel() <= level) {
			log(LEVEL[level] + ": " + getClassName(obj) + ": " + format(prop));
		}
	}

	public static void log(int level, Object obj, Throwable t) {
		if (logLevel() <= level) {
			log(LEVEL[level] + ": " + getClassName(obj) + ": " + format(t));

		}
	}

	public static void log(int level, String obj, List<Object> msgs) {
		if (logLevel() <= level) {

			log(LEVEL[level] + ": " + obj + ": " + format(msgs));

		}
	}

	public static void log(int level, String obj, Object msg) {
		if (logLevel() <= level) {
			log(LEVEL[level] + ": " + obj + ": " + msg);
		}
	}

	public static void log(int level, String obj, Object[] msgs) {
		if (logLevel() <= level) {

			log(LEVEL[level] + ": " + obj + ": " + format(msgs));
		}
	}

	public static void log(int level, String obj, Properties prop) {
		if (logLevel() <= level) {
			log(LEVEL[level] + ": " + obj + ": " + format(prop));

		}
	}

	public static void log(int level, String obj, Throwable t) {
		if (logLevel() <= level) {
			log(LEVEL[level] + ": " + obj + ": " + format(t));

		}
	}

	private static void log(String s) {
		System.out().println(s);
	}

	private static int logLevel() {
		return getLogLevel();
	}

	public static void setLogLevel(int level) {
		logLevel.set(new Integer(level));
	}

	private static int toLevel(String level) {
		for (int i = 0; i < LEVEL.length; i++) {
			if (LEVEL[i].equalsIgnoreCase(level)) {
				return i;
			}
		}
		return NONE;
	}
	
	public static void setLogLevel(String level) {
		logLevel.set(new Integer(toLevel(level)));
	}

	private Log() {
	}
}
